﻿using Unity.Burst;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using Unity.Mathematics;

namespace Mars.GpuInstance
{
    [BurstCompile(FloatPrecision = FloatPrecision.Low, FloatMode = FloatMode.Fast)]
    public struct GPUAnimatorControllerJob : IJobParallelFor
    {
        [NativeDisableContainerSafetyRestriction]
        public NativeArray<float4> gpuiCrowdAnimatorController;  // 0 to 4: x ->  minFrame, y -> maxFrame (negative if not looping), z -> speed, w -> startTime
        [NativeDisableContainerSafetyRestriction]
        public NativeArray<float4> gpuiAnimationData;            // index: 0 x -> frameNo1, y -> frameNo2, z -> frameNo3, w -> frameNo4
                                                                 // index: 1 x -> weight1, y -> weight2, z -> weight3, w -> weight4
        [ReadOnly]public float currentTime;
        [ReadOnly]public int frameRate;

        public void Execute(int index)
        {
            int animationIndex = index * 2;
            float MIN_SPEED = 0.000001f;
            
            if (animationIndex >= gpuiAnimationData.Length || animationIndex >= gpuiCrowdAnimatorController.Length)
            {
                return;
            }

            float4 animationData = gpuiAnimationData[animationIndex];
            float4 crowdAnimatorData = gpuiCrowdAnimatorController[animationIndex];
            int isLooping = (int) math.sign(crowdAnimatorData.y); // y == 0, 返回0， y>0返回1，y < 0 返回 -1
            crowdAnimatorData.y = crowdAnimatorData.y * isLooping; //设置成绝对值
            float clipTime = math.abs(currentTime - crowdAnimatorData.w) * crowdAnimatorData.z;
            float clipFrameCount = crowdAnimatorData.y - crowdAnimatorData.x;
            float length = clipFrameCount / frameRate;

            if (crowdAnimatorData.z > MIN_SPEED)
            {
                if (isLooping < 0 && clipTime > length) //非循环动画
                {
                    animationData.x = clipFrameCount;
                }
                else
                {
                    //frac取小数部分
                    float clipFrame = math.frac(clipTime / length) * clipFrameCount;
                    animationData.x = clipFrame;
                }
            }

            if (animationData.w > 0)
            {
                crowdAnimatorData = gpuiCrowdAnimatorController[animationIndex + 1];
                isLooping = (int) math.sign(crowdAnimatorData.y); // y == 0, 返回0， y>0返回1，y < 0 返回 -1
                crowdAnimatorData.y = crowdAnimatorData.y * isLooping; //设置成绝对值
                clipTime = math.abs(currentTime - crowdAnimatorData.w) * crowdAnimatorData.z;
                clipFrameCount = crowdAnimatorData.y - crowdAnimatorData.x;
                length = clipFrameCount / frameRate;

                if (crowdAnimatorData.z > MIN_SPEED)
                {
                    if (isLooping < 0 && clipTime > length) //非循环动画
                    {
                        animationData.z = clipFrameCount;
                    }
                    else
                    {
                        //frac取小数部分
                        float clipFrame = math.frac(clipTime / length) * clipFrameCount;
                        animationData.z = clipFrame;
                    }
                }
            }
            
            //Fix bone weights
            float totalWeight = animationData.y;
            totalWeight += animationData.w;
    
            if (totalWeight <= 0)
            {
                animationData.y = 1;
                animationData.w = 0;
            }
            else
            {
                totalWeight = 1 / totalWeight;

                animationData.y *= totalWeight;
                animationData.w *= totalWeight;
            }

            gpuiAnimationData[animationIndex] = animationData;
        }
    }
}
